const { isArray, isObject } = require('lodash')

/**
 * @description: 对象转字符串
 * @param {Object} 需要转换的对象
 * @param {ReplacerFunction} replacer
 * 该参数是一个函数，则在序列化过程中，被序列化的值的每个属性都会经过该函数的转换和处理；
 * @return {String} 转换后的字符串
 */
function stringify(obj = {}, replacer = null) {
  // 转换后的字符串
  let str = ''
  
  try {
    /** 
     * @description JSON.stringify()将值转换为相应的JSON格式：
     * 1. 转换值如果有 toJSON() 方法，该方法定义什么值将被序列化。
     * 2. 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
     * 3. 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
     * 4. undefined、任意的函数以及 symbol 值，在序列化过程中会被忽略（出现在非数组对象的属性值中时）或者被转换成 null（出现在数组中时）
     *    函数、undefined 被单独转换时，会返回 undefined，如JSON.stringify(function(){}) or JSON.stringify(undefined)。
     * 5. 对包含循环引用的对象（对象之间相互引用，形成无限循环）执行此方法，会抛出错误。
     * 6. 所有以 symbol 为属性键的属性都会被完全忽略掉，即便 replacer 参数中强制指定包含了它们。
     * 7. Date 日期调用了 toJSON() 将其转换为了 string 字符串（同Date.toISOString()），因此会被当做字符串处理。
     * 8. NaN 和 Infinity 格式的数值及 null 都会被当做 null。
     * 9. 其他类型的对象，包括 Map/Set/WeakMap/WeakSet，仅会序列化可枚举的属性。
    */
    // @ts-ignore 此处是因为 mdn文档和ts的类型不对应, 暂时以mdn为准
    str = JSON.stringify(obj, replacer)
    
  } catch (error) {
    str = isArray(obj) ? '[]' : isObject(obj) ? '{}' : String(obj)
  }
  
  return str
}

function completeString(str = '', length = 0) {
  return str + ' '.repeat(length - str.length)
}

exports.stringify = stringify

module.exports = {
  stringify,
  completeString
}